import mxgraph from 'pages/mxgraph/graph/index';
import { Point } from 'src/api/sysml-imports';
import graphUtil from "pages/mxgraph/graphUtil";
import { GraphShapeUtil } from '../../../pages/mxgraph/GraphShapeUtil';
import { dumpLog } from '@/constants/ErrorConfig';
const {
  mxConstants,
  mxCellState,
  mxEvent,
  mxConnectionHandler,
  mxPoint,
  mxEventObject,
  mxCell,
  mxGeometry,
  mxUtils,
  mxConnector
} = mxgraph;

export class ConnectionHandler extends mxConnectionHandler{
  constructor(){
    super(...arguments);
    this.movePreviewAway = false;
    this.waypointsEnabled = false;
    this.outlineConnect = true;
    this.livePreview = true;
    this.cursor = "crosshair";
  }
  init () {
    super.init(...arguments);

    this.constraintHandler.isEnabled = mxUtils.bind(this, function () {
      return this.graph.connectionHandler.isEnabled();
    });
  }
  insertEdge  (parent, id, value, source, target, style){

    let edge = this.createEdge(parent, id, value, source, target, style);
    if (!edge)  return;
    edge = this.graph.addEdge(edge, parent, source, target);
    this.graph.model.setStyle(edge, edge.getStyle());

    return edge;

  }
  createMarker () {
    let marker = super.createMarker(...arguments);
    let markerGetCell = marker.getCell;
    marker.getCell = mxUtils.bind(this, function (me) {
      let result = markerGetCell.apply(this, arguments);

      this.error = null;

      return result;
    });

    return marker;
  }
  getEdgeColor (valid){
    return (valid) ? '#000' : mxConstants.INVALID_COLOR;
  }
  getEdgeWidth(valid){
    return valid ? 2 : 1;
  }
  isCellEnabled (cell) {
    return !this.graph.isCellLocked(cell);
  }
  isCreateTarget (evt) {
    return (
      mxEvent.isControlDown(evt) || super.isCreateTarget(...arguments)
    );
  }
  createShape () {
    console.log('createShape------------');
    {
      //// Creates the edge preview
      const shape = new mxConnector([{ x: 0, Y: 0 }, { x: 0.5, Y: 0.5 }, { x: 1, Y: 1 }], '#000', 1);

      shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
        mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
      shape.scale = this.graph.view.scale;
      shape.pointerEvents = false;
      shape.isDashed = this.graph.createCurrentEdgeStyle().includes('dashed=1');
      shape.edgeStyle = "orthogonalEdgeStyle";
      //// shape.style = this.edgeState.cell.style;
      shape.init(this.graph.getView().getOverlayPane());
      mxEvent.redirectMouseEvents(shape.node, this.graph, null);

      return shape;
    }

  }
  createEdgeState() {
    console.log('createEdgeState--------------');
    let edgeCell = new mxCell(
      "",
      new mxGeometry(),
      this.graph.createCurrentEdgeStyle()
    );

    edgeCell.vertex = false;
    edgeCell.edge = true;

    let state = new mxCellState(
      this.graph.view,
      edgeCell,
      this.graph.getCellStyle(edgeCell)

    );

    return state;
  }
  mouseUp (sender, me) {
    let source = (this.previous != null) ? this.previous.cell : null;
    let target = null;

    if (this.constraintHandler.currentConstraint != null &&
      this.constraintHandler.currentFocus != null) {
      target = this.constraintHandler.currentFocus.cell;
    }

    if (target == null && this.currentState != null) {
      target = this.currentState.cell;
    }
    if (target == null && source != null) { //// && this.graph.inConnecting != 1
      console.log('已经有了连接第一点 点击在空白处 reset');
      this.reset();
      this.graph.resetMask();
      this.graph.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', me));

      return;
    }
    super.mouseUp(...arguments);

  };
  isValidTarget(cell){
    //// console.log('isValidTarget', cell);
    if (!cell) return false;
    if (cell.deep === 0) return false;
    let target = cell;
    const typeName = GraphShapeUtil.parseStName(target.umlShape.getTypeName());
    const behavior = this.graph.behaviors.get(typeName);
    const valid = behavior.isValidConnectTarget(app.ui.curEdgeType, this.previous.cell.umlShape, target.umlShape, this.graph.diagramNode);
    console.log(valid);
    return  valid;

    //// return edgeApi.isValidConnectTarget(app.ui.curEdgeType, this.previous.cell.typeName, target.typeName);
  }
  connect(source, target, evt, dropTarget){
    console.log('connect ------------');
    if (target != null || this.isCreateTarget(evt) || this.graph.allowDanglingEdges)
    {
      //// Uses the common parent of source and target or
      //// the default parent to insert the edge
      let model = this.graph.getModel();
      let terminalInserted = false;
      let edge = null;

      model.beginUpdate();
      try
      {
        if (source != null && target == null && !this.graph.isIgnoreTerminalEvent(evt) && this.isCreateTarget(evt))
        {
          target = this.createTargetVertex(evt, source);

          if (target != null)
          {
            dropTarget = this.graph.getDropTarget([target], evt, dropTarget);
            terminalInserted = true;

            //// Disables edges as drop targets if the target cell was created
            //// FIXME: Should not shift if vertex was aligned (same in Java)
            if (dropTarget == null || !this.graph.getModel().isEdge(dropTarget))
            {
              let pstate = this.graph.getView().getState(dropTarget);

              if (pstate != null)
              {
                let tmp = model.getGeometry(target);
                tmp.x -= pstate.origin.x;
                tmp.y -= pstate.origin.y;
              }
            }
            else
            {
              dropTarget = this.graph.getDefaultParent();
            }

            this.graph.addCell(target, dropTarget);
          }
        }

        let parent = this.graph.getDefaultParent();

        if (source != null && target != null &&
          model.getParent(source) == model.getParent(target) &&
          model.getParent(model.getParent(source)) != model.getRoot())
        {
          parent = model.getParent(source);

          if ((source.geometry != null && source.geometry.relative) &&
            (target.geometry != null && target.geometry.relative))
          {
            parent = model.getParent(parent);
          }
        }

        //// Uses the value of the preview edge state for inserting
        //// the new edge into the graph
        let value = null;
        let style = null;

        if (this.edgeState != null)
        {
          value = this.edgeState.cell.value;
          style = this.edgeState.cell.style;
        }

        edge = this.insertEdge(parent, null, value, source, target, style);

        if (edge != null)
        {
          //// Updates the connection constraints
          this.graph.setConnectionConstraint(edge, source, true, this.sourceConstraint);
          this.graph.setConnectionConstraint(edge, target, false, this.constraintHandler.currentConstraint);

          //// Uses geometry of the preview edge state
          if (this.edgeState != null)
          {
            model.setGeometry(edge, this.edgeState.cell.geometry);
          }

          let parent = model.getParent(source);

          //// Inserts edge before source
          if (this.isInsertBefore(edge, source, target, evt, dropTarget))
          {
            let index = null;
            let tmp = source;

            while (tmp.parent != null && tmp.geometry != null &&
              tmp.geometry.relative && tmp.parent != edge.parent)
            {
              tmp = this.graph.model.getParent(tmp);
            }

            if (tmp != null && tmp.parent != null && tmp.parent == edge.parent)
            {
              model.add(parent, edge, tmp.parent.getIndex(tmp));
            }
          }

          //// Makes sure the edge has a non-null, relative geometry
          let geo = model.getGeometry(edge);

          if (geo == null)
          {
            geo = new mxGeometry();
            geo.relative = true;

            model.setGeometry(edge, geo);
          }

          //// Uses scaled waypoints in geometry
          if (this.waypoints != null && this.waypoints.length > 0)
          {
            let s = this.graph.view.scale;
            let tr = this.graph.view.translate;
            geo.points = [];

            for (let i = 0; i < this.waypoints.length; i++)
            {
              let pt = this.waypoints[i];
              geo.points.push(new mxPoint(pt.x / s - tr.x, pt.y / s - tr.y));
            }
          }

          if (target == null)
          {
            let t = this.graph.view.translate;
            let s = this.graph.view.scale;
            let pt = (this.originalPoint != null) ?
              new mxPoint(this.originalPoint.x / s - t.x, this.originalPoint.y / s - t.y) :
              new mxPoint(this.currentPoint.x / s - t.x, this.currentPoint.y / s - t.y);
            pt.x -= this.graph.panDx / this.graph.view.scale;
            pt.y -= this.graph.panDy / this.graph.view.scale;
            geo.setTerminalPoint(pt, false);
          }

          this.fireEvent(new mxEventObject(mxEvent.CONNECT, 'cell', edge, 'terminal', target,
            'event', evt, 'target', dropTarget, 'terminalInserted', terminalInserted));
        }
      }
      //// catch (e)
      //// {
      ////   //// 注释掉了原来的mxLog
      ////   //// mxLog.show();
      ////   //// mxLog.debug(e.message);
      ////   throw e;
      //// }
      finally
      {
        model.endUpdate();
      }

      if (this.select)
      {
        this.selectCells(edge, (terminalInserted) ? target : null);
        app.ui.isConnectEvent = true;
      }
    }
  }
  //// 创建最后的连线
  createEdge(parent, id, value, source, target, style){
    
    //// todo 需检查是否可连接 app.ui.curEdgeType ,source,target
    let sourcePoint = new Point();
    let targetPoint = new Point();
    const outX = this.graph.diagramShape.bounds.x;
    const outY = this.graph.diagramShape.bounds.y;
    if (this.edgeState) {
      sourcePoint.x = this.edgeState.absolutePoints[0].x;
      sourcePoint.y = this.edgeState.absolutePoints[0].y;

      targetPoint.x = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 1].x;
      targetPoint.y = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 1].y;
    }
    const sourceConstraint = this.sourceConstraint; //// 起点
    const currentConstraint = this.constraintHandler.currentConstraint; //// 终点，如果连接点在内部则是null，如果连接点是边上则有point属性，代表比例位置
    let entryPoint;
    if (currentConstraint && currentConstraint.point){
      entryPoint = currentConstraint.point;
    }

    const typeName = app.ui.curEdgeType;

    const behavior = this.graph.behaviors.get(target.umlShape.getTypeName());
    targetPoint = { ...this.currentPoint };
    targetPoint.x -= outX;
    targetPoint.y -= outY;
    dumpLog('connectDrop', typeName, source.umlShape, target.umlShape, sourcePoint, targetPoint, entryPoint, this.graph.diagramNode);
    behavior.connectDrop(typeName, source.umlShape, target.umlShape, sourcePoint, targetPoint, entryPoint, this.graph.diagramNode);

    //// 以下逻辑放到Behavior的ConnectDrop中处理
    //// const isMessage = [ "Message", 'CallMessage', "SendMessage", "ReplyMessage", "CreateMessage", "DeleteMessage", "LostMessage", "FoundMessage", "MessageToSelf", "RecursiveMessage", "DiagonalMessage"];
    //// const isConstraint = ["TimeConstraint", "DurationConstraint"];

    //// if (isMessage.includes(typeName)){
    ////   console.log('创建message');
    ////   const res = graphUtil.post('/graph/edge/addLifeLine', {
    ////     typeName,
    ////     diagram: this.graph.diagram,
    ////     source: source,
    ////     target: target,
    ////     sourcePoint,
    ////     targetPoint,
    ////     entryPoint,
    ////     graph: this.graph
    ////   });

    ////   if ( res.data.status === -1) throw res.error;
    ////   graphUtil.expandParentSize(lifelineUtil.getLifelineShapeInGraph(this.graph));
    ////   //// 等后端完全好了再用全局刷新
    ////   app.$bus.emit('fresh-graph');
    ////   app.$bus.emit('model-add');

    ////   return null;
    //// } else if (isConstraint.includes(typeName)){

    ////   let { ajustEntryPoint, ajustExitPoint } = lifelineUtil.entryAndExitPointOfDurationConstraint(target, source, targetPoint, outX);

    ////   const res = graphUtil.post('/graph/edge/add', {
    ////     typeName,
    ////     diagram: this.graph.diagram,
    ////     sourceShape: source.umlShape,
    ////     targetShape: target.umlShape,
    ////     sourcePoint,
    ////     targetPoint,
    ////     entryPoint: ajustEntryPoint,
    ////     exitPoint: ajustExitPoint
    ////   });
    ////   if ( res.data.status === -1) throw res.error;

    ////   app.$bus.emit('model-add', { id: res.data.modelId });
    ////   app.$bus.emit('fresh-graph');
    //// } else {
    ////   const res = graphUtil.post('/graph/edge/add', {
    ////     typeName,
    ////     diagram: this.graph.diagram,
    ////     sourceShape: source.umlShape,
    ////     targetShape: target.umlShape,
    ////     sourcePoint,
    ////     targetPoint,
    ////     entryPoint

    ////   });
    ////   if ( res.data.status === -1) throw res.error;

    ////   app.$bus.emit('model-add', { id: res.data.modelId });
    ////   app.$bus.emit('fresh-graph');
    ////   return  null;
    //// }

  }
  //// Disables built-in connection starts
  isValidSource  (cell, me) {
    return false;
  }
  //// Handles parts of cells when cloning the source for new connections
  createTargetVertex  (evt, source) {
    let state = this.graph.view.getState(source);
    let style = state != null ? state.style : this.graph.getCellStyle(source);

    if (mxUtils.getValue(style, "part", false)) {
      let parent = this.graph.model.getParent(source);

      if (this.graph.model.isVertex(parent)) {
        source = parent;
      }
    }
    super.createTargetVertex(...arguments);
  };

}
